package com.studio.bill.swiperecyclerdemo.util;

import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Handler;
import android.os.Looper;
import android.widget.Toast;

import com.studio.bill.swiperecyclerdemo.MainApplication;

import org.apache.commons.codec.EncoderException;
import org.apache.commons.codec.net.URLCodec;

import java.io.File;
import java.io.IOException;
import java.util.Date;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.FormBody;
import okhttp3.Headers;
import okhttp3.HttpUrl;
import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;

public class HttpRequestManager {

    public static final String PROXY_IP = "proxy_ip";
    public static final String PROXY_PORT = "proxy_port";
    private static HttpRequestManager _INSTANCE = new HttpRequestManager();
    private OkHttpClient okHttpClient;

    public static HttpRequestManager manager() {
        return _INSTANCE;
    }

    public  OkHttpClient getOkClient() {
        return okHttpClient;
    }

    private HttpRequestManager() {
        OkHttpClient.Builder builder = new OkHttpClient.Builder();

        //暂时信任所有https证书
        try {
            // Create a trust manager that does not validate certificate chains
            final TrustManager[] trustAllCerts = new TrustManager[]{
                    new X509TrustManager() {
                        @Override
                        public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) {
                            //暂时信任所有https证书
                        }

                        @Override
                        public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) {
                            //暂时信任所有https证书
                        }

                        @Override
                        public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                            return new java.security.cert.X509Certificate[]{};
                        }
                    }
            };

            // Install the all-trusting trust manager
            final SSLContext sslContext = SSLContext.getInstance("SSL");
            sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
            // Create an ssl socket factory with our all-trusting manager
            final javax.net.ssl.SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();

            builder.sslSocketFactory(sslSocketFactory);
            builder.hostnameVerifier(new HostnameVerifier() {
                @Override
                public boolean verify(String hostname, SSLSession session) {
                    return true;
                }
            });

        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        okHttpClient = builder.build();
    }

    public static Headers getDefaultHeaders() {
        return getDefaultHeaders(null);
    }

    public static Headers getDefaultHeaders(Header[] headers) {
        String access_token = "";
        access_token = null == access_token ? "" : access_token;
        Context context = MainApplication.getInstance();
        String aopsID = "";
        PackageManager manager = MainApplication.getInstance().getPackageManager();
        String local_version = "";
        try {
            local_version = manager.getPackageInfo(context.getPackageName(), 0).versionName;
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        }
        Headers.Builder headerBuilder = new Headers.Builder();
        //check if the model is null
        String model = android.os.Build.MODEL;
        model = checkNameAndValue(model) ? model : "";
        String encodedModel = "";
        try {
            encodedModel = new URLCodec().encode(model);
        } catch (EncoderException e) {
            e.printStackTrace();
        }
        model = checkNameAndValue(model) ? model : encodedModel; // 编码中文model
        headerBuilder
                .add("tokenId", access_token)
                .add("aopsId", aopsID)
                .add("osVersion", model + "Android" + android.os.Build.VERSION.RELEASE)
                .add("token", access_token)
                .add("access_token", access_token)
                .add("aopsid", aopsID)
                .add("aopsID", aopsID)
                .add("entityID", "")
                .add("time_stamp", String.valueOf(new Date().getTime()))
                .add("terminalNo", "")
                .add("versionNo", "")
                .add("spartaId", "")
                .add("system_version", "AOPS_" + local_version);
        if (null == headers) {
            return headerBuilder.build();
        } else {
            for (Header header : headers) {
                headerBuilder.add(header.getName(), header.getValue());
            }
            return headerBuilder.build();
        }
    }

    public void post(final DefaultHttpRequest defaultHttpRequest) {
        FormBody.Builder builder = new FormBody.Builder();
        RequestParams requestParams = defaultHttpRequest.params();

        ConcurrentHashMap<String, String> urlparams = null == requestParams ? null : requestParams.getUrlParams();
        Set<Map.Entry<String, String>> entrySet = null == urlparams ? null : urlparams.entrySet();
        if (entrySet != null) {
            for (Map.Entry<String, String> entry : entrySet) {
                builder.add(entry.getKey(), entry.getValue());
            }
        }
        RequestBody requestBody = builder.build();
        Request okRequest = new Request.Builder().url(defaultHttpRequest.url()).headers(getDefaultHeaders()).post(requestBody).build();
        enqueueRequest(defaultHttpRequest, okRequest);
    }

    public void post(final DefaultHttpRequest defaultHttpRequest, Header[] headers) {
        FormBody.Builder builder = new FormBody.Builder();
        RequestParams requestParams = defaultHttpRequest.params();

        ConcurrentHashMap<String, String> urlparams = null == requestParams ? null : requestParams.getUrlParams();
        Set<Map.Entry<String, String>> entrySet = null == urlparams ? null : urlparams.entrySet();
        if (entrySet != null) {
            for (Map.Entry<String, String> entry : entrySet) {
                builder.add(entry.getKey(), entry.getValue());
            }
        }
        RequestBody requestBody = builder.build();
        Request okRequest = new Request.Builder().url(defaultHttpRequest.url()).headers(getDefaultHeaders()).post(requestBody).build();
        enqueueRequest(defaultHttpRequest, okRequest);
    }

    public void postJson(String json, DefaultHttpRequest defaultHttpRequest) {
        RequestBody requestBody = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), json);
        Request okRequest = new Request.Builder().url(defaultHttpRequest.url()).headers(getDefaultHeaders()).post(requestBody).build();
        enqueueRequest(defaultHttpRequest, okRequest);
    }

    public void postJson(String json, DefaultHttpRequest defaultHttpRequest, Header[] headers) {
        RequestBody requestBody = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), json);
        Request okRequest = new Request.Builder().url(defaultHttpRequest.url()).headers(getDefaultHeaders()).post(requestBody).build();
        enqueueRequest(defaultHttpRequest, okRequest);
    }

    public void postBytes(byte[] bytes, DefaultHttpRequest defaultHttpRequest, Header[] headers, final boolean gziped) {
        RequestBody requestBody = RequestBody.create(gziped ? MediaType.parse("application/x-gzip-compressed") : MediaType.parse("text/plain; charset=utf-8"), bytes);
        Request okRequest = new Request.Builder().url(defaultHttpRequest.url()).headers(getDefaultHeaders()).post(requestBody).build();
        enqueueRequest(defaultHttpRequest, okRequest);
    }

    public void postFile(File file, DefaultHttpRequest defaultHttpRequest) {
        RequestBody requestBody = RequestBody.create(MediaType.parse("application/octet-stream"), file);
        MultipartBody.Builder builder = new MultipartBody.Builder().setType(MultipartBody.FORM);
        builder.addPart(Headers.of("Content-Disposition", "form-data; name=\"file\";filename=" + "\"" + file.getName() + "\""), requestBody);
        Request okRequest = new Request.Builder().url(defaultHttpRequest.url()).headers(getDefaultHeaders()).post(builder.build()).build();
        enqueueRequest(defaultHttpRequest, okRequest);
    }

    public void get(DefaultHttpRequest defaultHttpRequest) {
        HttpUrl httpUrl = HttpUrl.parse(defaultHttpRequest.url());
        if (null != httpUrl) {
            HttpUrl.Builder urlBuilder = httpUrl.newBuilder();
            RequestParams requestParams = defaultHttpRequest.params();

            ConcurrentHashMap<String, String> urlparams = null == requestParams ? null : requestParams.getUrlParams();
            Set<Map.Entry<String, String>> entrySet = null == urlparams ? null : urlparams.entrySet();
            if (entrySet != null) {
                for (Map.Entry<String, String> entry : entrySet) {
                    urlBuilder.addQueryParameter(entry.getKey(), entry.getValue());
                }
            }
            Request okRequest = new Request.Builder().url(urlBuilder.build()).headers(getDefaultHeaders()).get().build();
            enqueueRequest(defaultHttpRequest, okRequest);
        } else {
            defaultHttpRequest.onFaliled(new ErrorCode(-1, "错误的url"));
        }
    }


    private void enqueueRequest(final DefaultHttpRequest defaultHttpRequest, final Request okRequest) {
        okHttpClient.newCall(okRequest).enqueue(new Callback() {

            @Override
            public void onFailure(Call call, IOException e) {
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        String msg = "网络不可用，请稍后重试";
                        if (defaultHttpRequest.showNetworkError()) {
                            toastShort(msg);
                        }
                        defaultHttpRequest.onFaliled(new ErrorCode(-1, msg));
                    }
                });
            }

            @Override
            public void onResponse(Call call, final Response response) throws IOException {
                try {
                    if (response.code() != 200) {
                        String result = response.body().string();
                        final ErrorCode finalErrorCode = new ErrorCode(response.code(), result);
                        runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                defaultHttpRequest.onFaliled(finalErrorCode);
                            }
                        });
                    }else if (response.code() / 100 == 2) {
                        final String result = response.body().string();
                        runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                defaultHttpRequest.onSuccess(result);
                            }
                        });
                    }
                } catch (final IOException e) {
                    e.printStackTrace();
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            defaultHttpRequest.onFaliled(new ErrorCode(-1, e.getMessage()));
                        }
                    });
                }
            }

        });
    }

    private Handler mainHandler = new Handler(Looper.getMainLooper());

    private void runOnUiThread(Runnable runnable) {
        mainHandler.post(runnable);
    }

    protected void toastShort(final String info) {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                Toast.makeText(MainApplication.getInstance(), info, Toast.LENGTH_SHORT).show();
            }
        });
    }

    public void cancelAllRequest() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                okHttpClient.connectionPool().evictAll();
            }
        }).start();
    }

    public interface Header {
        String getName();

        String getValue();

    }

    private static boolean checkNameAndValue(String value) {
        if (value == null) return false;
        for (int i = 0, length = value.length(); i < length; i++) {
            char c = value.charAt(i);
            if ((c <= '\u001f' && c != '\t') || c >= '\u007f') {
                return false;
            }
        }
        return true;
    }
}
